package modelo.reglas.composite.inner;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import modelo.Oferta;
import modelo.reglas.ISpecification;
import modelo.reglas.Specificable;

public class GroupSpecification <T extends Specificable> extends ISpecification<List<T>>{

	private final List<ISpecification<T>> groupConditions;
	private final Oferta ofertaOriginal;
        private int cantidadMinima;
        private int cantidadMaxima;
	
	/*
	 * Esta lista almacena los elementos que cumplieron el ultimo isSatisfiedBy
	 */
	private transient List<T> elementosQueCumplen;
	
	public GroupSpecification(Oferta ofertaOriginal,int min,int max,ISpecification<T> ... conditions) {
		this.groupConditions = Arrays.asList(conditions);
		elementosQueCumplen= new ArrayList<T>();
		this.ofertaOriginal = ofertaOriginal; 
                cantidadMinima = min;
                cantidadMaxima = max;
	}

	public GroupSpecification(Oferta ofertaOriginal,int min,int max,List<ISpecification<T>> groupConditions) {
		this.groupConditions = groupConditions;
		elementosQueCumplen= new ArrayList<T>();
		this.ofertaOriginal = ofertaOriginal;
                cantidadMinima = min;
                cantidadMaxima = max;
	}

	@Override
	public Boolean isSatisfiedBy(List<T> specificable) {
		List<ISpecification<T>> groupConditionsClone = new ArrayList<ISpecification<T>>(this.groupConditions);
		List<T> elementosQueCumplirian;
                int cantidadActual;

                elementosQueCumplen.clear();
		for (ISpecification<T> iSpecification : groupConditionsClone) {
			elementosQueCumplirian = new ArrayList<T>();
                        cantidadActual = 0;
			boolean algunoCumpleLaCondicion= false;
			for (T specificableItem : specificable) {
				if ( iSpecification.isSatisfiedBy(specificableItem) ){
					algunoCumpleLaCondicion = true;
                                        cantidadActual++;
					elementosQueCumplirian.add(specificableItem);
					
					//Listo, rompo este for y sigo con el siguiente filtro
                                        if((cantidadMaxima > 0)&&(cantidadActual >= cantidadMaxima))
                                            break;
				}
			}
                        if((cantidadActual >= cantidadMinima )||(cantidadMinima <= 0)){
                            for (T item : elementosQueCumplirian) {
                                elementosQueCumplen.add(item);
                            }
                            
                        }
                        
			
			if(!algunoCumpleLaCondicion){
				return false;
			}
		}
		
		return true;
	}

	public List<T> getElementosQueCumplen() {
		return elementosQueCumplen;
	}

	public Oferta getOfertaOriginal() {
		return ofertaOriginal;
	}
	
	
	

}
